<script setup lang="ts">
  import { useGetDepartmentOptions } from '@/services/module/department/useOptions'
  import { h, ref, watch } from 'vue'
  import { useCreateCode } from '@/services/module/code/useCode'
  import { CreateCodeTableRow } from './types'
  import {
    useGetProductOptions,
    useGetProductSpecOptions,
  } from '@/services/module/product/useProduct'
  import { debounce } from 'lodash'
  import { ElDivider, ElSelect, FormInstance } from 'element-plus'
  import { HMessage, HMessageBox } from '@/components/common/message'

  const {
    options: departmentOptions,
    getOptionsLoading: getDepartmentOptionsLoading,
    getOptions: getDepartmentOptions,
  } = useGetDepartmentOptions()
  const { createForm, createLoading, formSave, resetForm } = useCreateCode()
  const { productOptions, getProductOptionsParam, getProductOptionsLoading, getProductOptions } =
    useGetProductOptions()
  const {
    productSpecOptions,
    getProductSpecOptionsParam,
    getProductSpecOptionsLoading,
    getProductSpecOptions,
  } = useGetProductSpecOptions()

  defineOptions({
    name: 'CreateCodeModal',
  })

  const emits = defineEmits<{
    (e: 'update'): void
  }>()

  // 所属部门选择器组件实例
  const departmentSelectInstance = ref<InstanceType<typeof ElSelect> | null>(null)

  // 是否显示操作按钮
  const isShowOperate = ref(true)

  // 间距组件的间隔符
  const spacer = h(ElDivider, {
    direction: 'vertical',
    style: 'display: flex; align-items: center;',
  })

  // 序列号列表
  const codeList = ref<Array<CreateCodeTableRow>>([
    {
      activa: false,
      batchCode: '',
      code: '',
      contractNo: '',
      departmentIds: [],
      goodsId: '',
      registerCode: '',
      securityCode: '',
      specId: '',
      status: 1,
      storeStatus: 1,
      warrantyDay: '',
      warrantyStartTime: '',
      workOrderCode: '',
      goodName: '',
      goodSpec: '',
      codeSelectPopoverVisible: false,
      specSelectPopoverVisible: false,
      dl: '',
      specialBz: '',
      standard: '',
      voltage: '',
      xlh: '',
    },
  ])

  // 抽屉显示状态
  const visible = defineModel('modelValue', { type: Boolean, default: false })

  // 表单
  const form = ref<{ batchName: string; departmentIds: Array<string> }>({
    batchName: '',
    departmentIds: [],
  })

  // 表单校验规则
  const formRules = {
    departmentIds: [{ required: true, message: '请选择部门', trigger: ['blur', 'change'] }],
  }

  // 表单组件实例
  const formInstance = ref<FormInstance | null>(null)

  // 校验失败对象，用于给输入框添加校验失败后的样式
  const validateFailRaw = ref<{
    isFail: boolean
    codeIndex: number
    type: 'productCode' | 'productSpec' | 'serialNumber'
  }>({
    isFail: false,
    codeIndex: 0,
    type: 'productCode',
  })

  /**
   * 设置校验错误对象策略
   */
  const setValidateFailRawStrategy = {
    productCode: (index: number) => {
      validateFailRaw.value = {
        isFail: true,
        codeIndex: index,
        type: 'productCode',
      }
    },
    productSpec: (index: number) => {
      validateFailRaw.value = {
        isFail: true,
        codeIndex: index,
        type: 'productSpec',
      }
    },
    serialNumber: (index: number) => {
      validateFailRaw.value = {
        isFail: true,
        codeIndex: index,
        type: 'serialNumber',
      }
    },
  }

  /**
   * 表单校验策略
   */
  const formValidateStrategy = {
    formValidate: async () => {
      if (!formInstance.value) {
        throw new Error('校验失败')
      }

      try {
        await formInstance.value.validate()
        return true
      } catch (error) {
        throw new Error('校验失败')
      }
    },
    tableValidate: async () => {
      for (let i = 0; i < codeList.value.length; i++) {
        const code = codeList.value[i]
        if (!code.securityCode) {
          setValidateFailRawStrategy['serialNumber'](i)
          throw new Error('校验失败')
        }

        if (!code.goodsId) {
          setValidateFailRawStrategy['productCode'](i)
          throw new Error('校验失败')
        }

        if (!code.specId) {
          setValidateFailRawStrategy['productSpec'](i)
          throw new Error('校验失败')
        }
      }
      return ''
    },
  }

  /**
   * 序列号创建表单相关命令的接收者
   */
  const codeCreateFormReceiver = {
    assemble: () => {
      createForm.value.saveVoList = codeList.value.map((code) => {
        return {
          code: code.code,
          activa: code.activa,
          contractNo: code.contractNo,
          batchCode: form.value.batchName,
          departmentIds: form.value.departmentIds,
          goodsId: code.goodsId,
          securityCode: code.securityCode,
          registerCode: code.registerCode,
          specId: code.specId,
          status: code.status,
          storeStatus: code.storeStatus,
          warrantyDay: code.warrantyDay,
          warrantyStartTime: code.warrantyStartTime,
          workOrderCode: code.workOrderCode,
          dl: code.dl,
          specialBz: code.specialBz,
          standard: code.standard,
          voltage: code.voltage,
          xlh: code.xlh,
        }
      })
    },
  }

  /**
   * 序列号列表命令接收者
   */
  const codeListCommandReceiver: {
    initRaw: CreateCodeTableRow
    init: () => void
    push: () => void
  } = {
    initRaw: {
      activa: false,
      batchCode: '',
      code: '',
      contractNo: '',
      departmentIds: [],
      goodsId: '',
      registerCode: '',
      securityCode: '',
      specId: '',
      status: 1,
      storeStatus: 1,
      warrantyDay: '',
      warrantyStartTime: '',
      workOrderCode: '',
      goodName: '',
      goodSpec: '',
      codeSelectPopoverVisible: false,
      specSelectPopoverVisible: false,
      dl: '',
      specialBz: '',
      standard: '',
      voltage: '',
      xlh: '',
    },
    init: () => {
      codeList.value.length = 0
      codeList.value.push({ ...codeListCommandReceiver.initRaw })
    },
    push: () => {
      codeList.value.push({ ...codeListCommandReceiver.initRaw })
    },
  }

  /**
   * 创建表单组装命令
   * @param receiver - 接收者
   */
  const CodeCreateFormAssembleCommand = (receiver: { assemble: () => void }) => {
    return {
      execute: () => {
        receiver.assemble()
      },
    }
  }

  /**
   * 创建序列号列表初始化命令
   * @param receiver - 接收者
   */
  const CodeListInitCommand = (receiver: { init: () => void }) => {
    return {
      execute: () => {
        receiver.init()
      },
    }
  }

  /**
   * 创建序列号列表添加命令
   * @param receiver - 接收者
   */
  const CodeListPushCommand = (receiver: { push: () => void }) => {
    return {
      execute: () => {
        receiver.push()
      },
    }
  }

  /**
   * 添加按钮点击事件
   */
  const onAddClick = () => {
    CodeListPushCommand(codeListCommandReceiver).execute()
  }

  /**
   * 移除按钮点击事件
   * @param {number} index - 序列号索引
   */
  const handleRemoveClick = (index: number) => {
    codeList.value.splice(index, 1)
  }

  /**
   * 产品编号输入事件
   * @param {number} codeIndex - 序列号索引
   */
  const handleProductCodeInput = debounce((codeIndex: number) => {
    const code = codeList.value[codeIndex]
    if (!code) {
      return
    }

    getProductOptionsParam.value.name = code.code
    if (code.code) {
      codeList.value[codeIndex].codeSelectPopoverVisible = true
      getProductOptions()
    }
  })

  /**
   * 产品规格输入事件
   * @param {number} codeIndex - 序列号索引
   */
  const handleProductSpecInput = debounce((codeIndex: number) => {
    const code = codeList.value[codeIndex]
    if (!code) {
      return
    }

    getProductSpecOptionsParam.value.name = code.goodSpec
    if (code.code) {
      codeList.value[codeIndex].specSelectPopoverVisible = true
      getProductSpecOptions(code.goodsId)
    }
  })

  /**
   * 产品下拉选项点击事件
   * @param {ProductAPIResponse.ProductOption} productOption - 点击的下拉选项
   * @param {number} index - 序列号索引
   */
  const handleProductOptionsClick = async (
    productOption: ProductAPIResponse.ProductOption,
    index: number,
  ) => {
    const code = codeList.value[index]
    if (!code) {
      return false
    }

    codeList.value[index].code = productOption.code
    codeList.value[index].goodsId = productOption.id
    codeList.value[index].goodName = productOption.name
    await getProductSpecOptions(code.goodsId)
    const productSpecOption = productSpecOptions.value[0]
    if (productSpecOption) {
      codeList.value[index].specId = productSpecOption.id
      codeList.value[index].goodSpec = productSpecOption.name
      codeList.value[index].warrantyDay = String(productSpecOption.warrantyDay)
    }
  }

  /**
   * 产品规格下拉选项点击事件
   * @param {ProductAPIResponse.ProductSpecOption} productSpecOption - 点击的下拉选项
   * @param {number} index - 序列号索引
   */
  const handleProductSpecOptionsClick = (
    productSpecOption: ProductAPIResponse.ProductSpecOption,
    index: number,
  ) => {
    const code = codeList.value[index]
    if (!code) {
      return false
    }

    codeList.value[index].specId = productSpecOption.id
    codeList.value[index].goodSpec = productSpecOption.name
    codeList.value[index].warrantyDay = String(productSpecOption.warrantyDay)
  }

  /**
   * 设置质保状态
   * @param {number} index - 序列号索引
   */
  const setWarrantyStatus = (index: number) => {
    const code = codeList.value[index]
    if (!code) {
      return false
    }

    if (code.warrantyStartTime && code.warrantyDay) {
      const warrantyDayTimestamp = Number(code.warrantyDay) * 60 * 60 * 24 * 1000
      const timestamp = new Date(code.warrantyStartTime).getTime() + warrantyDayTimestamp
      const currentTimestamp = new Date().getTime()
      if (timestamp > currentTimestamp || timestamp === currentTimestamp) {
        codeList.value[index].status = 2
      } else {
        codeList.value[index].status = 3
      }
    } else {
      codeList.value[index].status = 1
    }
  }

  /**
   * 隐藏抽屉
   */
  const hideDrawer = () => {
    visible.value = false
    isShowOperate.value = true
    CodeListInitCommand(codeListCommandReceiver).execute()
    resetForm()
    form.value.batchName = ''
    form.value.departmentIds.length = 0
  }

  /**
   * 质保周期输入事件
   * @param {number} index - 序列号索引
   */
  const handleWarrantyDayInput = (index: number) => {
    const code = codeList.value[index]
    if (!code) {
      return false
    }

    codeList.value[index].warrantyDay = codeList.value[index].warrantyDay.replace(/[^\d]/g, '')
    setWarrantyStatus(index)
  }

  /**
   * 保存并创建点击事件
   */
  const onSaveClick = async () => {
    try {
      await formValidateStrategy.formValidate()
      await formValidateStrategy.tableValidate()

      const codeCreateFormAssembleCommand = CodeCreateFormAssembleCommand(codeCreateFormReceiver)
      codeCreateFormAssembleCommand.execute()

      const res = await formSave()
      if (res.code === 20000) {
        emits('update')
        hideDrawer()
        HMessage.success('创建完成')
        return
      }
      HMessageBox.error(res.message)
    } catch (error) {
      // error
    }
  }

  /**
   * 所属部门全选点击事件
   * @param departmentIdList - 部门ID列表
   */
  const handleDepartmentChange = (departmentIdList: Array<string>) => {
    if (departmentIdList.includes('all')) {
      form.value.departmentIds = departmentOptions.value
        .filter((item) => !item.disabled)
        .map((item) => item.id)

      if (departmentSelectInstance.value) {
        departmentSelectInstance.value.blur()
      }
    }
  }

  watch(visible, (value) => {
    if (value) {
      getDepartmentOptions()
    }
  })

  defineExpose({
    setCode: async (
      code: string,
      good: { id: string; specId: string; name: string; specName: string; code: string },
    ) => {
      isShowOperate.value = false
      codeList.value = [
        {
          specSelectPopoverVisible: false,
          codeSelectPopoverVisible: false,
          contractNo: '',
          activa: false,
          departmentIds: [],
          goodsId: good.id,
          specId: good.specId,
          registerCode: '',
          securityCode: code,
          status: 1,
          storeStatus: 1,
          warrantyDay: '',
          warrantyStartTime: '',
          workOrderCode: '',
          code: good.code,
          batchCode: '',
          goodName: good.name,
          goodSpec: good.specName,
          dl: '',
          specialBz: '',
          standard: '',
          voltage: '',
          xlh: '',
        },
      ]

      await getProductSpecOptions(good.id)
      const productSpecOption = productSpecOptions.value[0]
      if (productSpecOption) {
        codeList.value[0].specId = productSpecOption.id
        codeList.value[0].goodSpec = productSpecOption.name
        codeList.value[0].warrantyDay = String(productSpecOption.warrantyDay)
      }
    },
  })
</script>

<template>
  <h-drawer
    v-model="visible"
    title="创建序列号"
    :width="1200"
    unit="px"
    :loading="getDepartmentOptionsLoading || createLoading"
    @close="hideDrawer"
  >
    <div class="create-code-container">
      <div class="info-form">
        <el-form ref="formInstance" inline-message :inline="true" :model="form" :rules="formRules">
          <el-form-item label="批次名称" prop="batchName">
            <el-input v-model.trim="form.batchName" placeholder="请输入批次名称" />
          </el-form-item>
          <el-form-item label="所属部门" prop="departmentIds">
            <el-select
              ref="departmentSelectInstance"
              v-model="form.departmentIds"
              multiple
              collapse-tags
              collapse-tags-tooltip
              :max-collapse-tags="3"
              style="width: 320px"
              placeholder="请选择所属部门"
              @change="handleDepartmentChange"
            >
              <el-option :value="'all'" label="全选" />
              <el-option
                v-for="(department, departmentIndex) in departmentOptions"
                :key="departmentIndex"
                :label="department.name"
                :value="department.id"
                :disabled="!!department.disabled"
              />
            </el-select>
          </el-form-item>
        </el-form>
      </div>
      <div class="tip">
        <div class="title">创建序列号清单</div>
        <div class="desc">可批量创建产品序列号</div>
      </div>
      <el-table :max-height="600" width="100%" :border="true" :data="codeList">
        <!-- 序号 -->
        <el-table-column type="index" :width="50" :align="'center'" fixed="left" label="序号" />

        <!-- 序列号 -->
        <el-table-column label="序列号" width="120">
          <template #default="{ row, $index }">
            <el-input
              v-model="row.securityCode"
              placeholder="请输入序列号"
              :class="
                validateFailRaw.isFail &&
                validateFailRaw.codeIndex === $index &&
                validateFailRaw.type === 'serialNumber'
                  ? 'validate-fail-style'
                  : ''
              "
            />
          </template>
        </el-table-column>

        <!-- 产品编号 -->
        <el-table-column label="产品编号" width="140">
          <template #default="{ row, $index }">
            <el-popover :visible="row.codeSelectPopoverVisible" placement="bottom-end" :width="450">
              <template #reference>
                <el-input
                  v-model="row.code"
                  placeholder="请选择产品编号"
                  :class="
                    validateFailRaw.isFail &&
                    validateFailRaw.codeIndex === $index &&
                    validateFailRaw.type === 'productCode'
                      ? 'validate-fail-style'
                      : ''
                  "
                  @input="handleProductCodeInput($index)"
                  @blur="row.codeSelectPopoverVisible = false"
                />
              </template>

              <el-table
                v-loading="getProductOptionsLoading"
                :border="true"
                :data="productOptions.filter((item) => !item.disabled)"
                :max-height="400"
                @row-click="(productOption: ProductAPIResponse.ProductOption) => handleProductOptionsClick(productOption, $index)"
              >
                <el-table-column type="index" label="序号" width="50" :align="'center'" />
                <el-table-column label="产品编号" prop="code" width="120" show-overflow-tooltip />
                <el-table-column
                  label="产品名称"
                  prop="name"
                  min-width="100"
                  show-overflow-tooltip
                />
                <el-table-column label="产品分类" prop="type" width="80" show-overflow-tooltip />
              </el-table>
            </el-popover>
          </template>
        </el-table-column>

        <!-- 产品名称 -->
        <el-table-column label="名称" width="140">
          <template #default="{ row }">
            <el-input v-model="row.goodName" disabled />
          </template>
        </el-table-column>

        <!-- 产品规格 -->
        <el-table-column label="规格" width="140">
          <template #default="{ row, $index }">
            <el-popover :visible="row.specSelectPopoverVisible" placement="bottom-end" :width="450">
              <template #reference>
                <el-input
                  v-model="row.goodSpec"
                  placeholder="请选择产品规格"
                  :class="
                    validateFailRaw.isFail &&
                    validateFailRaw.codeIndex === $index &&
                    validateFailRaw.type === 'productSpec'
                      ? 'validate-fail-style'
                      : ''
                  "
                  @input="handleProductSpecInput($index)"
                  @blur="row.specSelectPopoverVisible = false"
                />
              </template>

              <el-table
                v-loading="getProductSpecOptionsLoading"
                :border="true"
                :data="productSpecOptions.filter((item) => !item.disabled)"
                :max-height="400"
                @row-click="(productSpecOption: ProductAPIResponse.ProductSpecOption) => handleProductSpecOptionsClick(productSpecOption, $index)"
              >
                <el-table-column type="index" label="序号" width="50" :align="'center'" />
                <el-table-column
                  label="规格名称"
                  prop="name"
                  min-width="120"
                  show-overflow-tooltip
                />
              </el-table>
            </el-popover>
          </template>
        </el-table-column>

        <!-- 合同号 -->
        <el-table-column label="合同号" width="140">
          <template #default="{ row }">
            <el-input v-model.trim="row.contractNo" placeholder="合同号" />
          </template>
        </el-table-column>

        <!-- 质保开始 -->
        <el-table-column label="质保开始" width="140">
          <template #default="{ row, $index }">
            <el-date-picker
              v-model="row.warrantyStartTime"
              type="date"
              value-format="YYYY-MM-DD"
              @change="setWarrantyStatus($index)"
            />
          </template>
        </el-table-column>

        <!-- 质保周期 -->
        <el-table-column label="质保周期" width="80">
          <template #default="{ row, $index }">
            <el-input v-model.trim="row.warrantyDay" @input="handleWarrantyDayInput($index)" />
          </template>
        </el-table-column>

        <!-- 质保状态 -->
        <el-table-column label="质保状态" width="75">
          <template #default="{ row }">
            <h-status v-if="row.status === 1" type="info">未质保</h-status>
            <h-status v-if="row.status === 2">质保中</h-status>
            <h-status v-if="row.status === 3" type="info">已过保</h-status>
          </template>
        </el-table-column>

        <!-- 激活状态 -->
        <el-table-column label="激活状态" width="100">
          <template #default="{ row }">
            <div style="display: flex; align-items: center; column-gap: 6px">
              <el-switch v-model="row.activa" size="small" />
              <span>{{ row.activa ? '已激活' : '未激活' }}</span>
            </div>
          </template>
        </el-table-column>

        <!-- 出库状态 -->
        <el-table-column label="出库状态" width="110">
          <template #default="{ row }">
            <el-select v-model="row.storeStatus" placeholder="请选择出库状态">
              <el-option :value="1" label="未出库" />
              <el-option :value="5" label="已出库" />
            </el-select>
          </template>
        </el-table-column>

        <!-- 系列号 -->
        <!-- <el-table-column label="系列号" width="110">
          <template #default="{ row }">
            <el-input v-model.trim="row.xlh" placeholder="系列号" />
          </template>
        </el-table-column> -->

        <!-- 电压 -->
        <!-- <el-table-column label="电压" width="110">
          <template #default="{ row }">
            <el-input v-model.trim="row.voltage" placeholder="电压" />
          </template>
        </el-table-column> -->

        <!-- 电流 -->
        <!-- <el-table-column label="电流" width="110">
          <template #default="{ row }">
            <el-input v-model.trim="row.dl" placeholder="电流" />
          </template>
        </el-table-column> -->

        <!-- 标准 -->
        <!-- <el-table-column label="标准" width="110">
          <template #default="{ row }">
            <el-input v-model.trim="row.standard" placeholder="标准" />
          </template>
        </el-table-column> -->

        <!-- 特殊要求 -->
        <!-- <el-table-column label="特殊要求" width="110">
          <template #default="{ row }">
            <el-input v-model.trim="row.specialBz" placeholder="特殊要求" />
          </template>
        </el-table-column> -->

        <!-- 资产码 -->
        <!-- <el-table-column label="资产码" width="120">
          <template #default="{ row }">
            <el-input v-model.trim="row.registerCode" placeholder="请输入资产码" />
          </template>
        </el-table-column> -->

        <!-- 平台订单号 -->
        <!-- <el-table-column label="平台订单号" width="150">
          <template #default="{ row }">
            <el-input v-model.trim="row.workOrderCode" placeholder="请输入平台订单号" />
          </template>
        </el-table-column> -->

        <!-- 操作 -->
        <el-table-column v-if="isShowOperate" label="操作" width="90" fixed="right">
          <template #default="{ $index }">
            <el-space :size="0" :spacer="spacer">
              <h-link @click="onAddClick">添加</h-link>
              <h-link v-if="codeList.length > 1" type="error" @click="handleRemoveClick($index)">
                移除
              </h-link>
            </el-space>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <template #footer>
      <h-button type="primary" is-modal @click="onSaveClick">保存并创建</h-button>
      <h-button is-modal @click="hideDrawer">取消</h-button>
    </template>
  </h-drawer>
</template>

<style scoped lang="scss">
  :deep(.el-date-editor) {
    width: 100%;
  }

  .create-code-container {
    display: flex;
    flex-direction: column;
    row-gap: 12px;

    .info-form {
      :deep(.el-form-item__label),
      :deep(.el-form-item__content) {
        height: 28px !important;
        line-height: 28px !important;
      }
    }

    .tip {
      display: flex;
      justify-content: space-between;
      background-color: rgba(0, 0, 0, 0.04);
      box-sizing: border-box;
      padding: 8px;
      border: 1px solid #dcdfe6;

      .desc {
        color: $primaryColor;
      }
    }
  }

  .validate-fail-style {
    :deep(.el-input__wrapper) {
      box-shadow: 0 0 0 1px #f56767 inset;

      .el-input__inner {
        &::placeholder {
          color: #f56767;
        }
      }
    }
  }
</style>
